/*
   Copyright (c) 2019 LinkedIn Corp.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

package com.linkedin.restli.tools.symbol;

import com.linkedin.parseq.function.Tuple3;
import java.util.List;


/**
 * Handle symbol table name generation and extraction of information.
 *
 * <p>These are meant ONLY for use by the {@link RestLiSymbolTableProvider} that prefixes server node uri and a prefix to
 * the symbol table name to implement a symmetric symbol table exchange protocol between Rest.li services. Symbol table
 * names generated by this class are encoded in the form of ServerNodeUri|SymbolTablePrefix-SymbolsHashCode</p>
 */
class SymbolTableNameHandler
{
  private static char SERVER_NODE_URI_PREFIX_TABLENAME_SEPARATOR = '|';
  private static String PREFIX_HASH_SEPARATOR = "-";

  private final String _symbolTablePrefix;
  private final String _serverNodeUri;

  /**
   * Constructor
   *
   * @param symbolTablePrefix  The prefix to use for symbol tables vended by this instance.
   * @param serverNodeUri      The URI on which the current service is running.
   */
  SymbolTableNameHandler(String symbolTablePrefix, String serverNodeUri)
  {
    _symbolTablePrefix = symbolTablePrefix;
    _serverNodeUri = serverNodeUri;
  }

  /**
   * Generate the symbol table name.
   *
   * @param symbols           The list of symbols.
   *
   * @return The generated symbol table name in the form of ServerNodeUri|SymbolTablePrefix-SymbolsHashCode
   */
  String generateName(List<String> symbols)
  {
    return _serverNodeUri + SERVER_NODE_URI_PREFIX_TABLENAME_SEPARATOR + _symbolTablePrefix
        + PREFIX_HASH_SEPARATOR + symbols.hashCode();
  }

  /**
   * Extracts just the table name, and whether the table is local (aka served from the same instance) or not.
   *
   * @param fullName The full table name.
   *
   * @return A tuple containing the url prefix from where the table was served the table name, and if the table
   * is local or remote.
   */
  Tuple3<String, String, Boolean> extractTableInfo(String fullName)
  {
    int index = fullName.indexOf(SERVER_NODE_URI_PREFIX_TABLENAME_SEPARATOR);

    // If no separator char was found, we assume it's a local table.
    if (index == -1)
    {
      return new Tuple3<>(_serverNodeUri, fullName, true);
    }

    if (index == 0 || index == fullName.length() - 1)
    {
      throw new RuntimeException("Unexpected name format for name: " + fullName);
    }

    String serverNodeUri = fullName.substring(0, index);
    String tableName = fullName.substring(index + 1);

    // A table is local if the server node URI matches the current server node URI.
    boolean isLocal = _serverNodeUri.equals(serverNodeUri);
    return new Tuple3<>(serverNodeUri, tableName, isLocal);
  }

  /**
   * Rename the original table name, replacing the existing url prefix with this instance's url prefix.
   *
   * @param existingTableName The existing table name.
   *
   * @return The new name with the url prefix in the existing name replaced with this instance's url prefix.
   */
  String replaceServerNodeUri(String existingTableName)
  {
    int index = existingTableName.indexOf(SERVER_NODE_URI_PREFIX_TABLENAME_SEPARATOR);

    if (index == -1 || index == 0 || index == existingTableName.length() - 1)
    {
      throw new RuntimeException("Unexpected name format for name: " + existingTableName);
    }

    return _serverNodeUri + SERVER_NODE_URI_PREFIX_TABLENAME_SEPARATOR + existingTableName.substring(index + 1);
  }
}
